import hashlib
import json
from datetime import timedelta
from functools import wraps
from typing import Any, Callable, Optional, Type, Union

from fastapi import Request, Response
from fastapi.responses import JSONResponse

from app.core.redis_conn import redis_conn


def generate_cache_key(
    prefix: str, request: Request, *, include_query: bool = True, include_user: bool = True, custom_key: str = None
) -> str:
    """
    生成缓存键
    :param prefix: 键前缀
    :param request: FastAPI请求对象
    :param include_query: 是否包含查询参数
    :param include_user: 是否包含用户信息
    :param custom_key: 自定义键
    """
    # 基础键：前缀 + 路径
    key_parts = [prefix, request.url.path]

    # 添加查询参数
    if include_query and request.query_params:
        sorted_params = sorted(request.query_params.items())
        key_parts.append(hashlib.md5(str(sorted_params).encode()).hexdigest())

    # 添加用户信息
    if include_user:
        user_id = getattr(request.state, "user", None)
        key_parts.append(str(getattr(user_id, "id", "anonymous")))

    # 添加自定义键
    if custom_key:
        key_parts.append(custom_key)

    return ":".join(key_parts)


class RouteCache:
    """路由缓存装饰器"""

    def __init__(
        self,
        *,
        prefix: str = "route",
        expire: Union[int, timedelta] = 300,
        include_query: bool = True,
        include_user: bool = True,
        custom_key: str = None,
        response_model: Optional[Type] = None,
        skip_cache_func: Optional[Callable[[Request], bool]] = None,
    ):
        """
        初始化缓存装饰器
        :param prefix: 缓存键前缀
        :param expire: 过期时间（秒或timedelta对象）
        :param include_query: 是否包含查询参数
        :param include_user: 是否包含用户信息
        :param custom_key: 自定义键
        :param response_model: 响应模型类型
        :param skip_cache_func: 跳过缓存的判断函数
        """
        self.prefix = prefix
        self.expire = expire.total_seconds() if isinstance(expire, timedelta) else expire
        self.include_query = include_query
        self.include_user = include_user
        self.custom_key = custom_key
        self.response_model = response_model
        self.skip_cache_func = skip_cache_func

    def __call__(self, func: Callable) -> Callable:
        @wraps(func)
        async def wrapper(*args: Any, **kwargs: Any) -> Any:
            # 获取请求对象
            request = next((arg for arg in args if isinstance(arg, Request)), kwargs.get("request"))
            if not request:
                raise ValueError("No request object found")

            # 检查是否跳过缓存
            if self.skip_cache_func and await self.skip_cache_func(request):
                return await func(*args, **kwargs)

            # 生成缓存键
            cache_key = generate_cache_key(
                self.prefix,
                request,
                include_query=self.include_query,
                include_user=self.include_user,
                custom_key=self.custom_key,
            )

            # 尝试获取缓存
            cached = await redis_conn.get(cache_key)
            if cached:
                data = json.loads(cached)
                if self.response_model:
                    return self.response_model(**data)
                return JSONResponse(content=data)

            # 执行原函数
            response = await func(*args, **kwargs)

            # 序列化响应
            if isinstance(response, Response):
                try:
                    data = json.loads(response.body.decode())
                except (json.JSONDecodeError, UnicodeDecodeError):
                    data = str(response.body)
            else:
                data = response

            # 缓存响应
            await redis_conn.set(cache_key, json.dumps(data), ex=self.expire)

            return response

        return wrapper


class CacheManager:
    """缓存管理工具"""

    @staticmethod
    async def clear_route_cache(prefix: str = "route", pattern: str = "*") -> int:
        """
        清除路由缓存
        :param prefix: 缓存键前缀
        :param pattern: 匹配模式
        :return: 清除的键数量
        """
        keys = await redis_conn.keys(f"{prefix}:{pattern}")
        if keys:
            return await redis_conn.delete(*keys)
        return 0

    @staticmethod
    async def clear_user_cache(user_id: Union[int, str]) -> int:
        """
        清除用户相关的缓存
        :param user_id: 用户ID
        :return: 清除的键数量
        """
        pattern = f"*:{user_id}:*"
        keys = await redis_conn.keys(pattern)
        if keys:
            return await redis_conn.delete(*keys)
        return 0

    @staticmethod
    async def clear_prefix_cache(prefix: str) -> int:
        """
        清除指定前缀的缓存
        :param prefix: 缓存键前缀
        :return: 清除的键数量
        """
        keys = await redis_conn.keys(f"{prefix}:*")
        if keys:
            return await redis_conn.delete(*keys)
        return 0

    @staticmethod
    async def get_cache_keys(pattern: str = "*") -> list:
        """
        获取缓存键列表
        :param pattern: 匹配模式
        :return: 键列表
        """
        return await redis_conn.keys(pattern)

    @staticmethod
    async def get_cache_info(key: str) -> dict:
        """
        获取缓存信息
        :param key: 缓存键
        :return: 缓存信息
        """
        ttl = await redis_conn.ttl(key)
        value = await redis_conn.get(key)
        return {"key": key, "ttl": ttl, "exists": value is not None, "size": len(value) if value else 0}


# 创建默认缓存管理器实例
cache_manager = CacheManager()
